#include "WorldObject.h"
int WorldObject::terrain_list_name = 0;
bool WorldObject::compiled = false;

WorldObject::WorldObject()
{
}

WorldObject::~WorldObject()
{
}
void WorldObject::Init() 
{
  Terrain_Generation();
  Compute_terrain_normals();
  /*if (!compiled)*/ LoadLists();
  pos.x = - HALF_TERRAIN;
  pos.z = - HALF_TERRAIN;
  pos.y = 0;
}



void WorldObject::Terrain_Generation()
{
//inizializzo la matrice dei vertici terreno
  int i,j = 0;
  for (i = 0; i < TERRAIN_POINTS; i++) 
        for (j = 0; j < TERRAIN_POINTS; j++)
            {
              terrain[i][j][0] = i * TERRAIN_PART_DIM;
              terrain[i][j][1] = 0.0; 
              terrain[i][j][2] = j * TERRAIN_PART_DIM;
            }  

     
//utilizzo una variante del fault algoritm (con le bolle)
    int x1, z1;
    int distance = 5;
    double displacement = 0.0; 
    double around[25];
    bool change = false;
    int r;   
    
    //genero il seme casuale
    srand ( time(NULL) );
    
    for (r = 0;r  < FAULT_ALG_MAX_ITE; r++) 
       {
         
        
         //cambio lo spiazamento e la dolcezza del bubbone
         if (r == 0)         displacement = 35, distance = 5, change = true;   //creo le montagne
         else if (r == 200)  displacement = 18, distance = 7, change = true;   //colline
         else if (r == 400)  displacement = 5, distance = 10, change = true;   //colline basse
         else if (r == 600 ) displacement = 1 , distance = 20, change = true;  //addolcisco un pò tutto
         
         //array per le dimensioni del bubbone ()
         if (change)
            {
             change = false;
             double  da = 90 / (distance + 1);
             double  ang = da;
             for (int var = 1;  var < distance  ; var++, ang +=  da)
                    around[var] = cos(ang * PI_DIV_180);
            }             
         
         
         //coordinate random del bubbone (un pò fuori dai limiti)
         x1 = rand() % (TERRAIN_POINTS + 10) - 5;
         z1 = rand() % (TERRAIN_POINTS + 10) - 5 ;
       
     
         //piazzo i bubboni nel terreno     
         for (i = 0; i < TERRAIN_POINTS; i++) 
            for (j = 0; j < TERRAIN_POINTS; j++)
                {
                    //distanza circolare col teorema di pitagora
                    double e = sqrt((float)(z1 - j) * (float)(z1 - j) + (float)(x1 - i) * (float)(x1 - i));
					int dist = (int)e; 
                    
                    //piazzo il bubbone
                    if ( dist >= 0  && dist < distance)  
                         terrain[i][j][1] += (around[dist] * +displacement);
                } 
             
        }
        
    
    //smooting   di tutto il territorio
    //righe sin 
    for (i = 1; i < TERRAIN_POINTS; i++) 
            for (j = 0; j < TERRAIN_POINTS; j++)
             terrain[i][j][1] = terrain[i-1][j][1]  * (1-SMOOTHING_COSTANT) +  terrain[i][j][1] * SMOOTHING_COSTANT;
                  
    //righe destra
    for(i = TERRAIN_POINTS-1;i < -1; i--)
        for (j = 0;j < TERRAIN_POINTS; j++)
            terrain[i][j][1] = terrain[i+1][j][1]  * (1-SMOOTHING_COSTANT) +  terrain[i][j][1] * SMOOTHING_COSTANT;

    //col bot tuop
    for(i = 0;i < TERRAIN_POINTS; i++)
        for (j = 1;j < TERRAIN_POINTS; j++)
            terrain[i][j][1] = terrain[i][j-1][1]  * (1-SMOOTHING_COSTANT) +  terrain[i][j][1] * SMOOTHING_COSTANT;

    //col top bot
    for(i = 0;i < TERRAIN_POINTS; i++)
        for (j = TERRAIN_POINTS; j < -1; j--)
            terrain[i][j][1] = terrain[i][j+1][1]  * (1-SMOOTHING_COSTANT) +  terrain[i][j][1] * SMOOTHING_COSTANT;
     
     
     
    //genero la mappa di texture 
     
    //trovo gli offeset di altezza    
    float min_height = terrain[0][0][1];
    float max_height = terrain[0][0][1];
    
    for (i = 0; i < TERRAIN_POINTS; i++) 
        for (j = 0; j < TERRAIN_POINTS; j++){
              if (terrain[i][j][1] < min_height) min_height = terrain[i][j][1] ; 
              if (terrain[i][j][1] >= max_height) max_height = terrain[i][j][1] ;
        }
        
   
    //genero la mappa di texture          

    float offset = max_height - min_height;
    float off_25 = ((offset / 100) *30) ;   //per l'erba scura              
    float off_60 = ((offset / 100) *62) ;   //per l'erba normale              
    float off_80 = ((offset / 100) *73) ;   //per la roccia 1
    
    
    
    //tolgo l'offest di altezza (il + basso a 0)
    for (i = 0; i < TERRAIN_POINTS; i++) 
        for (j = 0; j < TERRAIN_POINTS; j++)
              terrain[i][j][1] -=  min_height;
    
    for (i = 0; i < TERRAIN_POINTS-1; i++) 
              for (j = 0; j < TERRAIN_POINTS-1; j++)
              {
                //trovo il punto più basso di un quad  
                float d =terrain[i][j][1];
                if (d > terrain[i][j+1][1]) d = terrain[i][j+1][1];
                if (d > terrain[i+1][j+1][1]) d = terrain[i+1][j+1][1];
                if (d > terrain[i+1][j][1]) d = terrain[i+1][j][1];
                
                //assegno la texture secondo le altezze
                if(d <= off_25)
                     terrain_tex_map[i][j] = state->th->texNames[ERBASC]; //erba scura
                else if(d > off_25 && d <= off_60)
                     terrain_tex_map[i][j] = state->th->texNames[ERBA]; //erba norm
                else if(d > off_60 && d <= off_80)
                     terrain_tex_map[i][j] = state->th->texNames[ROCCIA];  //roccia1
                else 
                     terrain_tex_map[i][j] = state->th->texNames[ROCCIASC];
              }
    
    //stacco la texture map l'eraba dalle roccie con una texture speciale
    for (i = 1; i < TERRAIN_POINTS-2; i++) 
              for (j = 1; j < TERRAIN_POINTS-2; j++)
                 if (terrain_tex_map[i][j] == state->th->texNames[ERBA])
                 {
                    if ( terrain_tex_map[i+1][j+1] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i+1][j] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i+1][j-1] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i-1][j] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i-1][j-1] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i][j-1] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ROCCIA ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ROCCIA ])
                         terrain_tex_map[i][j] = state->th->texNames[ERBAROC];
                 }
    
        for (i = 1; i < TERRAIN_POINTS-2; i++) 
              for (j = 1; j < TERRAIN_POINTS-2; j++)
                 if (terrain_tex_map[i][j] == state->th->texNames[ROCCIA])
                 {
                    if ( terrain_tex_map[i+1][j+1] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i+1][j] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i+1][j-1] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i-1][j] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i-1][j-1] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i][j-1] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ROCCIASC ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ROCCIASC ])
                         terrain_tex_map[i][j] = state->th->texNames[ROCROC];
                 }
    
        for (i = 1; i < TERRAIN_POINTS-2; i++) 
              for (j = 1; j < TERRAIN_POINTS-2; j++)
                 if (terrain_tex_map[i][j] == state->th->texNames[ERBASC])
                 {
                    if ( terrain_tex_map[i+1][j+1] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i+1][j] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i+1][j-1] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i-1][j] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i-1][j-1] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i][j-1] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ERBA ] ||
                         terrain_tex_map[i-1][j+1] == state->th->texNames[ERBA ])
                         terrain_tex_map[i][j] = state->th->texNames[ERBERB];
                 }
                 
                 
                 
    //texture di erba con suolo messa a caso nell'erba
    for (i = 0; i < TERRAIN_POINTS-1; i++) 
              for (j = 0; j < TERRAIN_POINTS-1; j++)
                 if (terrain_tex_map[i][j] == state->th->texNames[ERBA])
                 {
                    if((rand() % 10) >= 8) terrain_tex_map[i][j] = state->th->texNames[23];
    
                 }
     

     
  


}
void WorldObject::LoadModel()
{
 
}

void WorldObject::Compute_terrain_normals()
{
 GeomCompute g;
 int i,j;
  
  for (i = 0; i < TERRAIN_POINTS-1; i++) 
              for (j = 0; j < TERRAIN_POINTS-1; j++)
                 {
                        
                    vertex_t v[3] = {{terrain[i][j][0],terrain[i][j][1],terrain[i][j][2]}, 
                                     {terrain[i][j+1][0],terrain[i][j+1][1],terrain[i][j+1][2]},
                                     {terrain[i+1][j][0],terrain[i+1][j][1],terrain[i+1][j][2]}};    
                  
                    vector_t n;      
                    g.normal(v,&n);
                    Nmap[i][j][0] = n.x; 
                    Nmap[i][j][1] = n.y;
                    Nmap[i][j][2] = n.z;   
                 }     
                            
 
 /*for (i = 10; i < 12; i++) 
              for (j = 23; j < 24; j++)
               printf("\n -> %f %f %f",Nmap[i][j][0],Nmap[i][j][1],Nmap[i][j][2]);*/
}

void WorldObject::LoadLists()
{
    //lista per le nuvole
    terrain_list_name = glGenLists(1);
    glNewList(terrain_list_name,GL_COMPILE);
        glEnable(GL_TEXTURE_2D);
       int i,j;
            for (i = 0; i < TERRAIN_POINTS-1; i++) 
              for (j = 0; j < TERRAIN_POINTS-4; j+=4)
              {
                 glBindTexture(GL_TEXTURE_2D,terrain_tex_map[i][j]);
                 glBegin(GL_QUADS);
                   glNormal3f(Nmap[i][j][0],Nmap[i][j][1],Nmap[i][j][2]);
                   glTexCoord2f(0.0f, 0.0f); glVertex3f(terrain[i][j][0],terrain[i][j][1],terrain[i][j][2]); 
                   glTexCoord2f(1.0f, 0.0f); glVertex3f(terrain[i][j+1][0],terrain[i][j+1][1],terrain[i][j+1][2]);
                   glTexCoord2f(1.0f, 1.0f); glVertex3f(terrain[i+1][j+1][0],terrain[i+1][j+1][1],terrain[i+1][j+1][2]); 
                   glTexCoord2f(0.0f, 1.0f); glVertex3f(terrain[i+1][j][0],terrain[i+1][j][1],terrain[i+1][j][2]); 
                 glEnd();
                 
                 glBindTexture(GL_TEXTURE_2D,terrain_tex_map[i][j+1]);
                 glBegin(GL_QUADS);
                   glNormal3f(Nmap[i][j+1][0],Nmap[i][j+1][1],Nmap[i][j+1][2]);
                   glTexCoord2f(0.0f, 0.0f); glVertex3f(terrain[i][j+1][0],terrain[i][j+1][1],terrain[i][j+1][2]); 
                   glTexCoord2f(1.0f, 0.0f); glVertex3f(terrain[i][j+2][0],terrain[i][j+2][1],terrain[i][j+2][2]);
                   glTexCoord2f(1.0f, 1.0f); glVertex3f(terrain[i+1][j+2][0],terrain[i+1][j+2][1],terrain[i+1][j+2][2]); 
                   glTexCoord2f(0.0f, 1.0f); glVertex3f(terrain[i+1][j+1][0],terrain[i+1][j+1][1],terrain[i+1][j+1][2]); 
                 glEnd();
                 
                 glBindTexture(GL_TEXTURE_2D,terrain_tex_map[i][j+2]);
                 glBegin(GL_QUADS);
                   glNormal3f(Nmap[i][j+2][0],Nmap[i][j+2][1],Nmap[i][j+2][2]);
                   glTexCoord2f(0.0f, 0.0f); glVertex3f(terrain[i][j+2][0],terrain[i][j+2][1],terrain[i][j+2][2]); 
                   glTexCoord2f(1.0f, 0.0f); glVertex3f(terrain[i][j+3][0],terrain[i][j+3][1],terrain[i][j+3][2]);
                   glTexCoord2f(1.0f, 1.0f); glVertex3f(terrain[i+1][j+3][0],terrain[i+1][j+3][1],terrain[i+1][j+3][2]); 
                   glTexCoord2f(0.0f, 1.0f); glVertex3f(terrain[i+1][j+2][0],terrain[i+1][j+2][1],terrain[i+1][j+2][2]); 
                 glEnd();
                 
                 glBindTexture(GL_TEXTURE_2D,terrain_tex_map[i][j+3]);
                 glBegin(GL_QUADS);
                   glNormal3f(Nmap[i][j+3][0],Nmap[i][j+3][1],Nmap[i][j+3][2]);
                   glTexCoord2f(0.0f, 0.0f); glVertex3f(terrain[i][j+3][0],terrain[i][j+3][1],terrain[i][j+3][2]); 
                   glTexCoord2f(1.0f, 0.0f); glVertex3f(terrain[i][j+4][0],terrain[i][j+4][1],terrain[i][j+4][2]);
                   glTexCoord2f(1.0f, 1.0f); glVertex3f(terrain[i+1][j+4][0],terrain[i+1][j+4][1],terrain[i+1][j+4][2]); 
                   glTexCoord2f(0.0f, 1.0f); glVertex3f(terrain[i+1][j+3][0],terrain[i+1][j+3][1],terrain[i+1][j+3][2]); 
                 glEnd();
              }

       glDisable(GL_TEXTURE_2D);
       
glEndList();
compiled = true;

}


void WorldObject::Draw(){
glPushMatrix();
       glTranslatef(pos.x,pos.y,pos.z);
       glCallList(terrain_list_name);
glPopMatrix();
}

float WorldObject::GetHeight(double x, double y)
{
   
   x +=  HALF_TERRAIN;
   y +=  HALF_TERRAIN;
   x /= TERRAIN_PART_DIM;
   y /= TERRAIN_PART_DIM;
  
  int xa = ((int)x); 
  int ya = ((int)y);
  
  xa = TERRAIN_POINTS - (++xa); 
  ya = TERRAIN_POINTS - (++ya);
 
  float d = terrain[xa][ya][1]; 
  if (d < terrain[xa][ya+1][1]) d =  terrain[xa][ya+1][1];
  if (d < terrain[xa+1][ya][1]) d =  terrain[xa+1][ya][1];
  if (d < terrain[xa+1][ya+1][1]) d =  terrain[xa+1][ya+1][1];
  

return -d;
}







